home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SOURCE.ZIP / DDIR.ASM < prev    next >
Assembly Source File  |  1986-02-05  |  13KB  |  441 lines

  1. ;    DDIR.ASM -- Double Column Sorted DIR Command
  2. ;    ========
  3. ;            (C) Copyright Charles Petzold, 1985
  4. ;
  5. ;            COM file format
  6. ;
  7.     
  8. CSEG        Segment
  9.  
  10.         Assume    CS:CSEG, DS:CSEG
  11.  
  12.         Org    002Ch            ; Offset of Environment
  13. Environment    Label    Byte
  14.  
  15.         Org    007Bh            ; Parameter for COMMAND.COM
  16. NewParameter    Label    Byte
  17.  
  18.         Org    0080h            ; Parameter passed to program
  19. OldParameter    Label    Byte    
  20.  
  21.         Org    0100h            ; Entry point
  22. Entry:        Jmp    Begin
  23.  
  24. ;    All Data
  25. ;    --------
  26.  
  27.         db    '(C) Copyright Charles Petzold, 1985'
  28.  
  29. DosVersMsg    db    "Needs DOS 2.0 +$"    ; Error messages
  30. MemAllocMsg    db    "Memory Problem$"
  31. CommandMsg    db    "COMMAND Problem$"
  32.  
  33. Comspec        db    "COMSPEC="        ; Search string in environment
  34. CommandAsciiz    dd    ?            ; Eventual pointer to COMMAND 
  35.  
  36. ParamBlock    dw    ?            ; Parameter Block for EXEC
  37.         dw    NewParameter,?        ; First ? must be replaced
  38.         dw    5Ch,?            ;    with Environment segment;
  39.         dw    6Ch,?            ;    others with this segment
  40.  
  41. OldInterrupt21    dd    ?            ; For vector address storage
  42.  
  43. BufferPtr    dw    Offset FileBuffer    ; For storing files listing
  44. CharCounter    dw    0            ; Keeps track of characters
  45. NowDoingFile    db    0            ; Flagged for file printed
  46. WithinFileList    db    0            ; Flagged for file list
  47. FileCounter    dw    0            ; Keeps track of files
  48. LineCounter    db    0            ; For pausing at screen end
  49.  
  50. PauseMessage    db    6 dup (205)," Press any key to continue "
  51.         db    6 dup (205),181 
  52. PauseMsgEnd    Label    Byte
  53.  
  54. ;    Check DOS Version
  55. ;    -----------------
  56.  
  57. Begin:        Mov    AH,30h            ; DOS Version function call
  58.         Int    21h            ; Call DOS
  59.         Cmp    AL,2            ; Check if version 2 
  60.         Jae    DosVersOK        ; If equal or over, all OK
  61.  
  62.         Mov    DX,Offset DosVersMsg    ; Wrong DOS version message
  63. ErrorExit:    Mov    AH,9            ; Set up for string write
  64.         Int    21h            ; Call DOS for message
  65.  
  66.         Int    20h            ; Dishonorable discharge
  67.  
  68. ;    Adjust stack and un-allocate rest of memory 
  69. ;    -------------------------------------------
  70.  
  71. DosVersOK:    Mov    DI,Offset FileBuffer    ; Place to save files
  72.         Mov    CX,528 * 39        ; Allow room for 528 files
  73.         Mov    AL,' '            ; Will clear with blanks
  74.         Cld                ; Forward direction
  75.         Rep    Stosb            ; Clear the area
  76.  
  77.         Mov     BX,(Offset FileBuffer) + (528 * 39) + 100h
  78.                          ; New end of program
  79.         Mov    SP,BX            ; Set the stack pointer
  80.         Add    BX,15            ; Add 15 for rounding
  81.         Mov    CL,4            ; Number of shifts
  82.         Shr    BX,CL            ; Convert AX to segment
  83.  
  84.         Mov    AH,4Ah            ; DOS call to shrink down
  85.         Int    21h            ;    allocated memory
  86.  
  87.         Mov    DX,Offset MemAllocMsg    ; Possible error message
  88.         Jc    ErrorExit        ; Only print it if Carry set
  89.  
  90. ;    Search for Comspec in Environment
  91. ;    ---------------------------------
  92.  
  93.         Mov    ES,[Environment]    ; Environment Segment
  94.         Sub    DI,DI            ; Start search at beginning
  95.         Cld                ; String increment to forward
  96.  
  97. TryThis:    Cmp    Byte Ptr ES:[DI],0    ; See if end of environment
  98.         Jz    NoFindComSpec        ; If so, we have failed
  99.         
  100.         Push    DI            ; Save environment pointer
  101.         Mov    SI,Offset ComSpec    ; String to search for
  102.         Mov    CX,8            ; Characters in search string
  103.         Repz    Cmpsb            ; Check if strings are same
  104.         Pop    DI            ; Get back the pointer
  105.  
  106.         Jz    FoundComspec        ; Found string only zero flag
  107.  
  108.         Sub    AL,AL            ; Zero out AL
  109.         Mov    CX,8000h        ; Set for big search
  110.         Repnz    Scasb            ; Find the next zero in string
  111.         Jmp    TryThis            ; And do the search from there
  112.  
  113. NoFindComSpec:    Mov    DX,Offset CommandMsg    ; Message for COMSPEC error
  114.         Jmp    ErrorExit        ; Print it and exit
  115.  
  116. FoundComspec:    Add    DI,8            ; So points after 'COMSPEC='
  117.         Mov    Word Ptr [CommandASCIIZ],DI    ; Save the address of
  118.         Mov    Word Ptr [CommandASCIIZ + 2],ES    ;    COMMAND ASCIIZ
  119.  
  120. ;     Set up parameter block for EXEC call
  121. ;    ------------------------------------
  122.  
  123.         Mov    [ParamBlock],ES        ; Segment of Environment string
  124.         Mov    [ParamBlock + 4],CS    ; Segment of this program
  125.         Mov    [ParamBlock + 8],CS    ;    so points to FCB's
  126.         Mov    [ParamBlock + 12],CS    ;    and NewParameter
  127.  
  128. ;    Save and set Interrupt 21h vector address
  129. ;    ----------------------------------------- 
  130.  
  131.         Mov    AX,3521h        ; DOS call to get Interrupt 21
  132.         Int    21h            ;    vector address
  133.         Mov    Word Ptr [OldInterrupt21],BX        ; Save offset
  134.         Mov    Word Ptr [OldInterrupt21 + 2],ES    ; And segment    
  135.  
  136.         Mov    DX,Offset NewInterrupt21; Address of new Interrupt 21 
  137.         Mov    AX,2521h        ; Do DOS call to
  138.         Int    21h            ;    set the new address
  139.  
  140. ;    Fix up new parameter for "/C DIR" String
  141. ;    ------------------------------------
  142.  
  143.         Mov    AL,[OldParameter]    ; Number of parameter chars     
  144.         Add    AL,5            ; We'll be adding five more
  145.         Mov    [NewParameter],AL    ; Save it
  146.         Mov    Word Ptr [NewParameter + 1],'C/'    ; i.e. "/C"
  147.         Mov    Word Ptr [NewParameter + 3],'ID'    ; Then "DI"    
  148.         Mov    Byte Ptr [NewParameter + 5],'R'        ; And "R"
  149.  
  150. ;     Load COMMAND.COM
  151. ;     -----------------
  152.         
  153.         Push    CS            ; Push this segment so we can
  154.         Pop    ES            ;    set ES to it
  155.         Mov    BX,Offset ParamBlock    ; ES:BX = address of block
  156.         Lds    DX,[CommandAsciiz]    ; DS:DX = address of ASCIIZ
  157.         Mov    AX,4B00h        ; EXEC call 4Bh, type 0
  158.         Int    21h            ; Load command processor
  159.  
  160. ;     Return from COMMAND.COM
  161. ;    -----------------------
  162.  
  163.         Mov    AX,CS        ; Get this segment in AX
  164.         Mov    DS,AX        ; Set DS to it
  165.         Mov    SS,AX        ; And SS for stack segment
  166.         Mov    SP,(Offset FileBuffer) + (528 * 39) + 100h
  167.                     ; Set Stack again
  168.  
  169.         PushF            ; Save Carry for error check 
  170.         Push    DS        ; Save DS during next call
  171.  
  172.         Mov    DX,Word Ptr [OldInterrupt21]    ; Old Int 21 offset
  173.         Mov    DS,Word Ptr [OldInterrupt21 + 2]; and segment
  174.         Mov    AX,2521h        ; Call DOS to set vector
  175.         Int    21h            ;    address to original    
  176.  
  177.         Pop    DS            ; Restore DS to this segment
  178.         PopF                ; Get back Carry flage
  179.  
  180.         Jnc    NormalEnd        ; Continue if no error
  181.  
  182.         Mov    DX,Offset CommandMsg    ; Otherwise we'll print error
  183.         Jmp    ErrorExit        ;    message and exit
  184.  
  185. NormalEnd:    Int    20h            ; Terminate program
  186.  
  187. ;    New Interrupt 21h
  188. ;    -----------------
  189.  
  190. NewInterrupt21    Proc    Far
  191.  
  192.         Sti                ; Allow further interrupts
  193.         Cmp    AH,40h            ; Check if file / device write
  194.         Je    CheckHandle        ; If so, continue checks
  195.  
  196. SkipIntercept:    Jmp    CS:[OldInterrupt21]    ; Just jump to old interrupt
  197.  
  198. CheckHandle:    Cmp    BX,1            ; Check if standard output
  199.         Jne    SkipIntercept        ; Not interested if not
  200.  
  201.         PushF                ; Push all registers that
  202.         Push    AX            ;    we'll be messing with
  203.         Push    CX
  204.         Push    SI
  205.         Push    DI
  206.         Push    ES
  207.  
  208.         Push    CS            ; Push the code segment
  209.         Pop    ES            ; So we can set ES to it
  210.         Cld                ; Forward for string transfers
  211.         Mov    SI,DX            ; Now DS:SI = text source
  212.         Mov    DI,CS:[BufferPtr]    ; And ES:DI = text destination
  213.  
  214.         Cmp    CX,2            ; See if two chars to write
  215.         Jne    RegularChars        ; If not, can't be CR/LF
  216.  
  217.         Cmp    Word Ptr DS:[SI],0A0Dh    ; See if CR/LF being written
  218.         Jne    RegularChars        ; Skip rest if not CR/LF
  219.  
  220.         Mov    CX,CS:[CharCounter]    ; Get characters in line
  221.         Mov    CS:[CharCounter],0    ; Start at new line
  222.         Cmp    CS:[NowDoingFile],1    ; See if CR/LF terminates file
  223.         Jnz    AllowTransfer        ; If not, just write to screen
  224.  
  225.         Mov    AX,39            ; Max characters per line
  226.         Sub    AX,CX            ; Subtract those passed 
  227.         Add    CS:[BufferPtr],AX    ; Kick up pointer by that
  228.         Mov    CS:[NowDoingFile],0    ; Finished with file
  229.         Jmp    PopAndReturn        ; So just return to COMMAND
  230.  
  231. RegularChars:    Add    CS:[CharCounter],CX    ; Kick up counter by number
  232.         Cmp    CS:[CharCounter],CX    ; See if beginning of line
  233.         Jne    NotLineBegin        ; If not, must be in middle
  234.  
  235.         Cmp    Byte Ptr DS:[SI],' '    ; See if first char is blank
  236.         Jne    ItsAFile        ; If not, it's a file line
  237.  
  238.         Cmp    CS:[WithinFileList],1    ; See if doing file listing
  239.         Jne    AllowTransfer        ; If not, just print stuff
  240.  
  241.         Call    SortAndList        ; Files done -- sort and list
  242.         Mov    CS:[WithinFileList],0    ; Not doing files now
  243.         Jmp    Short AllowTransfer    ; So just print the stuff
  244.  
  245. ItsAFile:    Cmp    CS:[FileCounter],528    ; See if 11 buffer filled up
  246.         Jb    NotTooManyFiles        ; If not just continue
  247.  
  248.         Push    CX            ; Otherwise, save this register
  249.         Call    SortAndList        ; Print all up to now
  250.         Mov    CS:[FileCounter],0    ; Reset the counter
  251.         Mov    DI,Offset FileBuffer    ; And the pointer
  252.         Mov    CS:[BufferPtr],DI    ; Save the pointer
  253.         Mov    CX,528 * 39        ; Will clear for 528 files
  254.         Mov    AL,' '            ; With a blank
  255.         Rep    Stosb            ; Clear it out
  256.         Pop    CX            ; And get back register
  257.  
  258. NotTooManyFiles:Mov    CS:[WithinFileList],1    ; We're doing files now
  259.         Mov    CS:[NowDoingFile],1    ; And a file in particular
  260.         Inc    CS:[FileCounter]    ; So kick up this counter
  261.  
  262. NotLineBegin:    Cmp    CS:[NowDoingFile],1    ; See if doing files
  263.         Je    StoreCharacters        ; If so, store the stuff
  264.  
  265. AllowTransfer:    Pop    ES            ; Pop all the registers
  266.         Pop    DI
  267.         Pop    SI
  268.         Pop    CX
  269.         Pop    AX
  270.         PopF
  271.  
  272.         Jmp    SkipIntercept        ; And go to DOS for print
  273.  
  274. StoreCharacters:Mov    DI,CS:[BufferPtr]    ; Set destination
  275.         Rep    Movsb            ; Move characters to buffer
  276.         Mov    CS:[BufferPtr],DI    ; And save new pointer    
  277.  
  278. PopAndReturn:    Pop    ES            ; Pop all the registers
  279.         Pop    DI
  280.         Pop    SI
  281.         Pop    CX
  282.         Pop    AX
  283.         PopF
  284.  
  285.         Mov    AX,CX            ; Set for COMMAND.COM
  286.         Clc                ; No error here 
  287.         Ret    2            ; Return with CY flag cleared
  288.  
  289. NewInterrupt21    EndP
  290.  
  291. ;    Sort Files
  292. ;    ----------
  293.  
  294. SortAndList:    Push    BX            ; Push a bunch of registers
  295.         Push    DX
  296.         Push    SI
  297.         Push    DS
  298.  
  299.         Push    CS            ; Push CS
  300.         Pop    DS            ;    so we can set DS to it
  301.         Assume    DS:CSEG            ; And inform the assembler
  302.  
  303.         Mov    DI,Offset FileBuffer    ; This is the beginning
  304.         Mov    CX,[FileCounter]    ; Number of files to sort
  305.         Dec    CX            ; Loop needs one less than that 
  306.         Jcxz    AllSorted        ; But zero means only one file
  307.  
  308. SortLoop1:    Push    CX            ; Save the file counter
  309.         Mov    SI,DI            ; Set source to destination
  310.  
  311. SortLoop2:    Add    SI,39            ; Set source to next file
  312.  
  313.         Push    CX            ; Save the counter,
  314.         Push    SI            ;    compare source,
  315.         Push    DI            ;    and compare destination
  316.  
  317.         Mov    CX,39            ; 39 characters to compare
  318.         Repz    Cmpsb            ; Do the compare
  319.         Jae    NoSwitch        ; Jump if already in order
  320.  
  321.         Pop    DI            ; Get back these registers
  322.         Pop    SI
  323.  
  324.         Push    SI            ; And push them again for move
  325.         Push    DI
  326.  
  327.         Mov    CX,39            ; 39 characters
  328. SwitchLoop:    Mov    AL,ES:[DI]        ; Character from destination 
  329.         Movsb                ; Source to destination
  330.         Mov    DS:[SI - 1],AL        ; Character to source
  331.         Loop    SwitchLoop        ; For the rest of the line
  332.  
  333. NoSwitch:    Pop    DI            ; Get back the registers
  334.         Pop    SI
  335.         Pop    CX
  336.         Loop    SortLoop2        ; And loop for next file
  337.  
  338.         Pop    CX            ; Get back file counter 
  339.         Add    DI,39            ; Compare with next file
  340.         Loop    SortLoop1        ; And loop again
  341.  
  342. ;    Now Display Sorted Files
  343. ;    ------------------------
  344.  
  345. AllSorted:    Mov    SI,Offset FileBuffer    ; This is the beginning
  346.         Mov    CX,[FileCounter]    ; Number of files to list
  347.         Inc    CX            ; In case CX is odd
  348.         Shr    CX,1            ; CX now is number of lines
  349.  
  350. SetIncrement:    Mov    BX,24 * 39        ; Increment for double list
  351.         Cmp    CX,24            ; But use it only if a full
  352.         Jae    LineLoop        ;    screen is printed    
  353.  
  354.         Mov    AX,39            ; Otherwise find increment
  355.         Mul    CX            ;    by multiplying CX by 39
  356.         Mov    BX,AX            ; And make that the increment
  357.  
  358. LineLoop:    Call    PrintFile        ; Print the first column file
  359.         Mov    AL,' '            ; Skip one space
  360.         Call    PrintChar        ;    by printing blank
  361.         Mov    AL,179            ; Put a line down the middle
  362.         Call    PrintChar
  363.         Mov    AL,' '            ; Skip another space
  364.         Call    PrintChar
  365.  
  366.         Add    SI,BX            ; Bump up source by increment
  367.         Sub    SI,39             ; But kick down by 39
  368.  
  369.         Call    PrintFile        ; Print the second column file
  370.         Call    CRLF            ; And terminate line
  371.  
  372.         Sub    SI,BX            ; Bring pointer back down
  373.  
  374.         Inc    [LineCounter]        ; One more line completed
  375.         Cmp    [LineCounter],24    ; Have we done whole screen?
  376.         Jz    PauseAtEnd        ; If so, gotta pause now
  377.  
  378.         Loop    LineLoop        ; Otherwise just loop
  379.         Jmp    Short AllFinished    ; And jump out when done
  380.  
  381. PauseAtEnd:    Mov    [LineCounter],0        ; Reset the counter
  382.         Add    SI,BX            ; Go to next file
  383.  
  384.         Push    BX            ; Save these registers
  385.         Push    CX
  386.         Mov    DX,Offset PauseMessage    ; Test to print
  387.         Mov    CX,Offset PauseMsgEnd - Offset PauseMessage
  388.                         ; Number of characters
  389.         Mov    BX,2            ; Standard ERROR Output
  390.         Mov    AH,40h            ; Display to screen
  391.         Int    21h            ; By calling DOS 
  392.         Pop    CX            ; Retrieve pushed registers 
  393.         Pop    BX
  394.  
  395.         Mov    AH,8            ; Wait for character
  396.         Int    21h            ; Through DOS call
  397.  
  398.         Call    CRLF            ; Go to next line 
  399.  
  400.         Loop    SetIncrement        ; And recalculate increment
  401.  
  402. AllFinished:    Pop    DS            ; Done with subroutine
  403.         Pop    SI
  404.         Pop    DX
  405.         Pop    BX
  406.         Ret                ; So return to caller
  407.  
  408. ;    Display Routines
  409. ;    ----------------
  410.  
  411. PrintChar:    Mov    DL,AL            ; Print character in AL
  412.         Mov    AH,2            ; By simple DOS call
  413.         Int    21h
  414.         Ret                ; And return
  415.  
  416. CRLF:        Mov    AL,13            ; Print a carriage return
  417.         Call    PrintChar
  418.         Mov    AL,10            ; And a line feed
  419.         Call    PrintChar
  420.         Ret                ; And return
  421.  
  422. PrintString:    Lodsb                ; Get character from SI
  423.         Call    PrintChar        ; Print it
  424.         Loop    PrintString        ; Do that CX times
  425.         Ret                ; And return
  426.  
  427. PrintFile:    Push    CX            ; Save the counter
  428.         Mov    CX,32            ; Bytes for Name, Size, & Date
  429.         Call    PrintString        ; Print it    
  430.         Inc    SI            ; Skip one space before time
  431.         Mov    CX,6            ; Bytes for Time
  432.         Call    PrintString        ; It's a print!
  433.         Pop    CX        
  434.         Ret                ; And return
  435.  
  436. FileBuffer    Label    Byte            ; Points to end of code
  437.  
  438. CSEG        EndS                ; End of segment
  439.  
  440.         End    Entry            ; Denotes entry point
  441.